package com.zjdiepu.www.commpent;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.aliyun.oss.common.utils.BinaryUtil;
import com.zjdiepu.www.base.lang.HttpClientException;

/**
 * 项目名称：dp-base <br/> 
 * 类名称：VerifyOSSCallback <br/>  
 * 类描述： 回调验证<br/>    
 * 创建人：xiongxiaotun <br/> 
 * 创建时间：2017年3月30日 上午11:25:09  <br/>   
 * 修改人：xiongxiaotun <br/> 
 * 修改时间：2017年3月30日 上午11:25:09   <br/>  
 * 修改备注：    <br/> 
 * @version V1.0   <br/>
 */
@Component
public class VerifyOSSCallback {
	private static final Logger logger = LoggerFactory.getLogger(OSSCommpent.class);
	
	@Resource
	private HttpClient httpClient;
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: verifyOSSCallbackRequest  <br/>
	 * @Description: 验证回调请求 <br/>
	 * @param request
	 * @param ossCallbackBody
	 * @return
	 * @throws NumberFormatException
	 * @throws HttpClientException
	 * @throws SocketTimeoutException
	 * @throws UnsupportedEncodingException
	 * @version V1.0  <br/>
	 */
	public boolean verifyOSSCallbackRequest(HttpServletRequest request, String ossCallbackBody) throws NumberFormatException, HttpClientException, SocketTimeoutException, UnsupportedEncodingException {
		boolean ret = false;	
		String autorizationInput = new String(request.getHeader("Authorization"));
		String pubKeyInput = request.getHeader("x-oss-pub-key-url");
		byte[] authorization = BinaryUtil.fromBase64String(autorizationInput);
		byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput);
		String pubKeyAddr = new String(pubKey);
		if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/") && !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/"))
		{
			logger.error("pub key addr must be oss addrss");
			return false;
		}
		String retString = httpClient.get(pubKeyAddr, new HashMap<String, String>());
		retString = retString.replace("-----BEGIN PUBLIC KEY-----", "");
		retString = retString.replace("-----END PUBLIC KEY-----", "");
		String queryString = request.getQueryString();
		String uri = request.getRequestURI();
		String decodeUri = URLDecoder.decode(uri, "UTF-8");
		String authStr = decodeUri;
		if (queryString != null && !queryString.equals("")) {
			authStr += "?" + queryString;
		}
		authStr += "\n" + ossCallbackBody;
		ret = doCheck(authStr, authorization, retString);
		return ret;
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: GetPostBody  <br/>
	 * @Description:获取请求内容 <br/>
	 * @param is
	 * @param contentLen
	 * @return
	 * @version V1.0  <br/>
	 */
	public String getPostBody(InputStream is, int contentLen) {
		if (contentLen > 0) {
			int readLen = 0;
			int readLengthThisTime = 0;
			byte[] message = new byte[contentLen];
			try {
				while (readLen != contentLen) {
					readLengthThisTime = is.read(message, readLen, contentLen - readLen);
					if (readLengthThisTime == -1) {// Should not happen.
						break;
					}
					readLen += readLengthThisTime;
				}
				return new String(message);
			} catch (IOException e) {
				logger.error("get post body exception.", e);
			}
		}
		return "";
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: response  <br/>
	 * @Description: 应答阿里OSS服务器  <br/>
	 * @param request
	 * @param response
	 * @param results
	 * @param status
	 * @throws IOException
	 * @version V1.0  <br/>
	 */
	public void response(HttpServletRequest request, HttpServletResponse response, String results, int status) throws IOException {
		String callbackFunName = request.getParameter("callback");
		response.addHeader("Content-Length", String.valueOf(results.length()));
		if (StringUtils.isBlank(callbackFunName)) {
			response.getWriter().println(results);
		} else {
			response.getWriter().println(callbackFunName + "( " + results + " )");
		}
		response.setStatus(status);
		response.flushBuffer();
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: doCheck  <br/>
	 * @Description: 验证方法 <br/>
	 * @param content
	 * @param sign
	 * @param publicKey
	 * @return
	 * @version V1.0  <br/>
	 */
	public static boolean doCheck(String content, byte[] sign, String publicKey) {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			byte[] encodedKey = BinaryUtil.fromBase64String(publicKey);
			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
			Signature signature = Signature.getInstance("MD5withRSA");
			signature.initVerify(pubKey);
			signature.update(content.getBytes());
			boolean bverify = signature.verify(sign);
			return bverify;

		} catch (Exception e) {
			logger.error("verify sign exception.", e);
		}
		return false;
	}
}
